<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<script>
    // 1.柯里化.html
    // 第一版本
    // 主要作用存参数 第二次就执行函数了!!!
    /* var curry = function(fn){
        // arguments是列表具有length属性，不是数组。将arguments变成数组
        var args = [].slice.call(arguments, 1)
        // 返回一个函数声明，可以执行
        return function(){
            var newArgs = args.concat([].slice.call(arguments))
            // 返回函数执行结果
            return fn.apply(this, newArgs)
        }
    }
    function add(a,b){
        return a+b;
    }
    var addCurry = curry(add, 1, 2)
    console.log(addCurry()) */


    /* 第二版 */
   /*  function sub_curry(fn){
        var args = [].slice.call(arguments,1)
        return function(){
            return fn.apply(this,args.concat([].slice.call(arguments)))
        }
    }
    function curry(fn,length){
        length = length || fn.length // function.length表示该函数的形参个数 和arguments.length不同，实参个数
        var slice = Array.prototype.slice
        return function(){
            if(arguments.length < length){
                var combined = [fn].concat(slice.call(arguments))
                return curry(sub_curry.apply(this,combined),length-arguments.length)
            }else{
                return fn.apply(this,arguments)
            }
        }
    } */
    /* 简易版 */
    function curry(fn,args){
        const  length = fn.length
        args = args || []
        return function(){
            /* 进行深拷贝 */
            let _args = args.slice(0), arg, i;
            for(i=0;i<arguments.length;++i){
                arg = arguments[i]
                _args.push(arg)
            }
            if(args.length === length){
                return fn.apply(this,_args)
            }else{
                return curry.apply(this, fn,_args)
            }
        }
    }
    /* 第三版 */
    function curry(fn,args,holes){
        length = fn.length
        args = args || []
        holes = holes || []
        return function(){
            var _args = args.slice(0),
            _holes = holes.slice(0),
            argsLen = args.length,
            holesLen = holes.length,
            arg, i, index = 0;
            
            for(i=0;i<arguments.length;++i){
                arg = arguments[i]
                // 处理类似 fn(1, _, _, 4)(_, 3) 这种情况，index 需要指向 holes 正确的下标
                if(arg === "_"&&holesLen){
                    index++;
                    if(index > holesLen){
                        _args.push(arg)
                        _holes.push(argsLen-1+index-holesLen)
                    }
                }
                // 处理类似 fn(1)(_) 这种情况
                else if(arg === "_"){
                    _args.push(agr);
                    _holes.push(argsLen+i)
                }
                 // 处理类似 fn(_, 2)(1) 这种情况
                else if(holesLen){
                    // fn(_, 2)(_, 3)
                    if(index >= holesLen){
                        _args.push(arg)
                    // fn(_, 2)(1) 用参数 1 替换占位符
                    }else{
                        _args.splice(_holes[index],1,arg)
                        _holes.splice(index,1)
                    }
                }else{
                    _args.push(arg)
                }
            }
            if(_holes.length || _args.length<length){
                return curry.call(this,fn,_args,_holes)
            }else{
                return fn.apply(this,_args)
            }
        }
    }
</script>
<body>
    
</body>
</html>